/**
 * This file is a part of VideoCut package.
 * ---------------------------------------------------------------------- 
 * Copyright (C) 2007-2008 troorl
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * ---------------------------------------------------------------------- 
 *
 * @author troorl <troorl@gmail.com>
 */

#include "TFfmpeg.h"
#include <QtGui>

TFfmpeg::TFfmpeg()
{
	
}

int TFfmpeg::init(const char *mrl)
{
	av_register_all();
	
	// Open video file
	if(av_open_input_file(&this->pFormatCtx, mrl, NULL, 0, NULL) != 0)
		return CANT_OPEN_FILE; // Couldn't open file
	
	// Retrieve stream information
	if(av_find_stream_info(this->pFormatCtx) < 0)
		return CANT_FIND_VIDEO_CODEC; // Couldn't find stream information
	
	dump_format(this->pFormatCtx, 0, mrl, 0);
	
	int i;

	// Find the first video stream
	videoStream = -1;
	
	for(i = 0; i < this->pFormatCtx->nb_streams; i++)
	{
		if(this->pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
		{
			videoStream = i;
			break;
		}
	}
	
	if(videoStream == -1)
			return CANT_FIND_VIDEO_CODEC; // Didn't find a video stream

	// Get a pointer to the codec context for the video stream
	this->pCodecCtx = pFormatCtx->streams[videoStream]->codec;
	

	// Find the decoder for the video stream
	this->pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
	
	char buf[256];
	avcodec_string(buf, sizeof(buf), pCodecCtx, 0);
	double fps = av_q2d (pFormatCtx->streams[videoStream]->r_frame_rate);
	
	if(this->pCodec == NULL)
	{
		fprintf(stderr, "Unsupported codec!\n");
		return CANT_FIND_VIDEO_CODEC; // Codec not found
	}
	// Open codec
	if(avcodec_open(pCodecCtx, pCodec) < 0)
		return CANT_FIND_VIDEO_CODEC; // Could not open codec
	
	
	// Allocate video frame
	this->pFrame = avcodec_alloc_frame();
	
	// Allocate an AVFrame structure
	this->pFrameRGB = avcodec_alloc_frame();
	if(this->pFrameRGB == NULL)
		return CANT_FIND_VIDEO_CODEC;
	
	
	int numBytes;
	
	// Determine required buffer size and allocate buffer
	numBytes = avpicture_get_size(PIX_FMT_RGBA32, pCodecCtx->width, this->pCodecCtx->height);
	this->buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
	
	
	// Assign appropriate parts of buffer to image planes in pFrameRGB
	// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
	// of AVPicture
	avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGBA32, pCodecCtx->width, pCodecCtx->height);
}

const char *TFfmpeg::videoCodec()
{
	return "";
}

const char *TFfmpeg::audioCodec()
{
	return "";
}

int TFfmpeg::getLength()
{
	return pFormatCtx->duration * 1000 / AV_TIME_BASE;
}

const unsigned char *TFfmpeg::getCurrentFrame(int frameNumber, int *width, int *height) 
{
	frameNumber = frameNumber * AV_TIME_BASE / 1000;
	
	*width = pCodecCtx->width;
	*height = pCodecCtx->height;
	
	int frameFinished;
	AVPacket packet;

	
	//seeking
	av_seek_frame(pFormatCtx, -1, frameNumber, AVSEEK_FLAG_BACKWARD);
	avcodec_flush_buffers(pCodecCtx);
	
	while(av_read_frame(pFormatCtx, &packet) >= 0)
	{
		// Is this a packet from the video stream?
		if(packet.stream_index == videoStream)
		{
			// Decode video frame
			avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);
	
			// Did we get a video frame?
			if(frameFinished)
			{	
				// Convert the image from its native format to RGB
				img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGBA32, (AVPicture*)pFrame, pCodecCtx->pix_fmt,  pCodecCtx->width, pCodecCtx->height);
			
				// Save the frame to disk
				//SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, minute);
				break;
			}
		}
	}
	
	av_free_packet(&packet);

	//QImage *tmp_image = new QImage(pFrameRGB->data[0], *width, *height, QImage::Format_RGB32);
	QString tmpstr = "/home/troorl/Desktop/AVcodec_test/" + QString::number(frameNumber) + ".png";
	//tmp_image->save(tmpstr);
		
	return /*(unsigned char *)*/pFrameRGB->data[0];
}

void TFfmpeg::close()
{
	av_free(buffer);
	av_free(pFrameRGB);

	// Free the YUV frame
	av_free(pFrame);

	// Close the codec
	avcodec_close(pCodecCtx);

	// Close the video file
	av_close_input_file(pFormatCtx);
}
